using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Configuration;
using System.ComponentModel;
using System.Collections.Generic;
using Irc.Objects;
using Irc.Events;

namespace Irc.Net
{
	public partial class Main : Form
	{
		public event EventHandler<NetworkEventArgs> NewConnection;

		protected void OnNewConnectionEvent(Network network)
		{
			NetworkEventArgs e = new NetworkEventArgs();
			e.Network = network;
			if(NewConnection != null)
				NewConnection(this, e);
		}

		public Main()
		{
			Location = SettingsManager.Instance.Location;
			InitializeComponent();
			PluginManager.Instance.PluginLoading += delegate(object sender, PluginEventArgs e){
					string name = e.Plugin.FullName;
					if(DialogResult.No == MessageBox.Show("Do you want to load "+name+"?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1))
						e.Cancel = false;
				};
			PluginManager.Instance.EnablePlugins(this);

			#region commands
			CommandManager.Instance.RegisterCommand("join", JoinChannelCmd);
			CommandManager.Instance.RegisterCommand("part", PartChannelCmd);
			CommandManager.Instance.RegisterCommand("me", MeCmd);
			CommandManager.Instance.RegisterCommand("act", MeCmd);
			CommandManager.Instance.RegisterCommand("hop", HopCmd);
			CommandManager.Instance.RegisterCommand("cycle", HopCmd);
			CommandManager.Instance.RegisterCommand("hopall", HopAllCmd);
			CommandManager.Instance.RegisterCommand("cycleall", HopAllCmd);
			CommandManager.Instance.RegisterCommand("quit", QuitCmd);
			#endregion

			OpenConnection(null, null);
		}

		public Client[] ConnectedNetworks
		{
			get {
				List<Client> clients = new List<Client>();
				foreach(Form f in MdiChildren)
				{
					Network network = f as Network;
					if(network != null && network.Client.Registered)
						clients.Add(network.Client);
				}
				return clients.ToArray();
			}
		}
		public Client[] AllNetworks
		{
			get
			{
				List<Client> clients = new List<Client>();
				foreach(Form f in MdiChildren)
				{
					Network network = f as Network;
					if(network != null)
						clients.Add(network.Client);
				}
				return clients.ToArray();
			}
		}

		internal void JoinChannelCmd(Client clientObject, Target target, string[] parameters)
		{
			if(parameters.Length > 0)
				for(int i = 0; i < parameters.Length; i++)
					clientObject.JoinChannel(parameters[0]);
			else if(target is Channel)
				((Channel)target).Rejoin();
		}
		internal void PartChannelCmd(Client clientObject, Target target, string[] parameters)
		{
			if(parameters.Length > 0)
				for(int i = 0; i < parameters.Length; i++)
					if(clientObject.Channels.ContainsKey(parameters[i]))
						clientObject.Channels[parameters[i]].Part();
			else if(target is Channel)
				((Channel)target).Part();
		}
		internal void QuitCmd(Client clientObject, Target target, string[] parameters)
		{
			if(ConnectedNetworks.Length > 0 && DialogResult.Yes == MessageBox.Show("Are you sure you want to exit? You still have open networks!", "Alert!", MessageBoxButtons.YesNo))
			{
				if(parameters.Length > 0)
					foreach(Client c in ConnectedNetworks)
						c.Disconnect(String.Join(" ", parameters));
				Application.Exit();
			}
		}
		internal void MeCmd(Client clientObject, Target target, string[] parameters)
		{
			if(parameters.Length > 0)
			{
				Irc.Objects.Message m = null;
				if(target is Channel)
					m = new PublicAction();
				else if (target is Nickname)
					m = new PrivateAction();
				m.Target = target;
				m.Text = String.Join(" ", parameters);
				clientObject.Act(m);
			}
			else
			{
				Irc.Objects.Message m = new Irc.Objects.Message();
				m.Text = "[Error] What do you want to say?";
				((Network)FindChildByName(clientObject.Server)).ServerWindow.AddMessage(m);
			}
		}
		internal void HopCmd(Client clientObject, Target target, string[] parameters)
		{
			if(target == null || target is Nickname)
			{
				Irc.Objects.Message m = new Irc.Objects.Message();
				m.Text = "[Error] You can't rejoin that target!";
				((Network)FindChildByName(clientObject.Server)).ServerWindow.AddMessage(m);
			}
			else
				((Channel)target).Rejoin();
		}
		internal void HopAllCmd(Client clientObject, Target target, string[] parameters)
		{
			foreach(Client client in ConnectedNetworks)
			{
				foreach(KeyValuePair<string,Channel> channel in client.Channels)
				{
					channel.Value.Rejoin();
				}
			}
		}

		private Form FindChildByName(string name)
		{
			foreach(Form f in MdiChildren)
				if(f.Name == name)
					return f;
			return null;
		}
		public static void ParseCommand(object sender, KeyEventArgs e)
		{
			TextBox cmdText = ((TextBox)sender);
			if(e.KeyCode == Keys.Enter && cmdText.Text != "")
			{
				Network owner = (Network)cmdText.FindForm();
				TabPage tab = owner.FindTabByControl(cmdText);
				Target target = null;
				if(tab.Controls[0] is ChannelTab)
					target = ((ChannelTab)tab.Controls[0]).Target;
				else if(tab.Controls[0] is MessageTab)
					target = ((MessageTab)tab.Controls[0]).Target;
				Client client = owner.Client;
				string command = cmdText.Text;
				e.Handled = e.SuppressKeyPress = true;
				if(command.StartsWith(SettingsManager.Instance["CommandCharacter"]))
				{
					command = command.Substring(SettingsManager.Instance["CommandCharacter"].Length);
					string[] split = command.Split(new char[]{' '}, 2);
					string action = split[0];
					string[] parameters = new string[split.Length-1];
					Array.Copy(split, 1, parameters, 0, split.Length-1);
					if(!CommandManager.Instance.Raise(client, target, action, parameters))
					{
						Irc.Objects.Message m = new Irc.Objects.Message();
						m.Text = "[Error] Unrecognized command \""+action+"\"";
						owner.ServerWindow.AddMessage(m);
					}
				}
				else
				{
					if(target is Channel)
						((Channel)target).Say(command);
					else if(target is Nickname)
					{
						PrivateMessage pm = new PrivateMessage();
						pm.Target = (Nickname)target;
						pm.Text = command;
						owner.Client.Say(pm);
					}
					else
					{
						Irc.Objects.Message m = new Irc.Objects.Message();
						m.Text = "[Error] You cannot just randomly say things to the server!";
						owner.ServerWindow.AddMessage(m);
					}
				}
				cmdText.Text = String.Empty;
			}
		}
		private void OpenConnection(object sender, EventArgs e)
		{
			Connect c = new Connect();
			if(c.ShowDialog() == DialogResult.OK)
			{
				Network n = new Network(this, c.connectString.Text, c.nickname.Text, c.realname.Text, c.username.Text, c.password.Text);
				OnNewConnectionEvent(n);
				if(c.AutoConnect.Checked == true)
					n.Connect();
			}
		}

		private void ExitClient(object sender, EventArgs e)
		{
			Application.Exit();
		}
		private void Minimize(object sender, EventArgs e)
		{
			if(WindowState == FormWindowState.Minimized)
				FormHide(sender, e);
			if(WindowState == FormWindowState.Normal)
				FormShow(sender, e);
		}
		private void FormShow(object sender, EventArgs e)
		{
			Show();
			tray.Visible = false;
			Activate();
			WindowState = FormWindowState.Normal;
		}
		private void FormHide(object sender, EventArgs e)
		{
			Hide();
			tray.Visible = true;
			WindowState = FormWindowState.Minimized;
		}
		private void DoubleClickTray(object sender, MouseEventArgs e)
		{
			FormShow(sender, null);
		}
		
		private void FormExit(object sender, FormClosingEventArgs e)
		{
			if(ConnectedNetworks.Length > 0 && MessageBox.Show("Are you sure you want to exit? You still have open networks!", "Alert!", MessageBoxButtons.YesNo) == DialogResult.No)
			{
				e.Cancel = true;
			}
			if(e.Cancel != true)
				SettingsManager.Instance.Location = Location;
		}

		private void QuitApp(object sender, EventArgs e)
		{
			Close();
		}

		private void UpdateList(object sender, CancelEventArgs e)
		{
			ToolStripItem quit = trayStrip.Items[trayStrip.Items.Count-1];
			ToolStripItem show = trayStrip.Items[trayStrip.Items.Count-2];
			trayStrip.Items.Clear();
			foreach(Form f in MdiChildren)
			{
				trayStrip.Items.Insert(0, new ToolStripMenuItem(f.Text, null, delegate(object s, EventArgs ev) {
						Show();
						tray.Visible = false;
						WindowState = FormWindowState.Normal;
						ActivateMdiChild(FindChildByName(((ToolStripItem)s).Text));
					}));
			}
			trayStrip.Items.Add(new ToolStripSeparator());
			trayStrip.Items.Add(show);
			trayStrip.Items.Add(quit);
		}

		private void CurrentConnectClick(object sender, EventArgs e)
		{
			((Network)ActiveMdiChild).Connect();
		}

		private void DisconnectCurrentClick(object sender, EventArgs e)
		{
			((Network)ActiveMdiChild).Disconnect();
		}

		private void ConnectAllClick(object sender, EventArgs e)
		{
			foreach(Form f in MdiChildren)
			{
				Network n = f as Network;
				if(n != null)
					n.Connect();
			}
		}

		private void DisconnectAllClick(object sender, EventArgs e)
		{
			foreach(Form f in MdiChildren)
			{
				Network n = f as Network;
				if(n != null)
					n.Disconnect();
			}
		}
	}
	public class NetworkEventArgs : EventArgs
	{
		private Network network;
		public Network Network {
			get { return network; }
			set { network = value; }
		}
	}
}
